DOCKER 6 分钟 6,019 字

SSH 端口切换脚本 - Ubuntu 专用

0阅读
#!/bin/bash
# SSH 端口切换脚本 - Ubuntu 专用
# 功能:切换到传统模式 + 修改端口为 719
# 适用:Ubuntu 16.04 - 24.04
# ============================================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 新端口
NEW_PORT=719
BACKUP_DIR="/root/ssh_backup_$(date +%Y%m%d_%H%M%S)"

# 打印函数
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# ============================================================
# 1. 检查端口
# ============================================================
check_port() {
    print_info "检查端口 $NEW_PORT 是否被占用..."
    if ss -tulnp 2>/dev/null | grep -q ":$NEW_PORT "; then
        print_error "端口 $NEW_PORT 已被占用!"
        ss -tulnp | grep ":$NEW_PORT "
        print_warning "请停止占用该端口的服务或更换端口"
        exit 1
    fi
    print_success "端口 $NEW_PORT 可用"
}

# ============================================================
# 2. 备份配置
# ============================================================
backup_config() {
    print_info "备份当前 SSH 配置到 $BACKUP_DIR..."
    mkdir -p "$BACKUP_DIR"
    cp /etc/ssh/sshd_config "$BACKUP_DIR/sshd_config.bak"
    print_success "备份完成"
}

# ============================================================
# 3. 配置 SSH
# ============================================================
configure_ssh() {
    print_info "配置 SSH 端口为 $NEW_PORT(传统模式)..."
    
    # 生成新的配置文件
    sudo cat > /etc/ssh/sshd_config << 'EOF'
# ============================================================
# SSH 服务器配置 - 传统模式
# 端口: 719
# 认证: 仅公钥
# ============================================================

# 网络配置
Port 719
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::

# 主机密钥
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# 认证配置(仅公钥)
PermitRootLogin yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM no

# 日志
SyslogFacility AUTH
LogLevel INFO

# 安全配置
LoginGraceTime 2m
StrictModes yes
MaxAuthTries 3
MaxSessions 10

# 其他
X11Forwarding yes
PrintMotd no
UseDNS no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server

# 禁用 .rhosts
IgnoreRhosts yes
HostbasedAuthentication no
EOF

    print_success "SSH 配置完成"
}

# ============================================================
# 4. 切换到传统模式
# ============================================================
switch_to_traditional() {
    print_info "切换到传统 SSH 模式..."
    
    # 停止并屏蔽 socket 模式
    sudo systemctl stop ssh.socket 2>/dev/null || true
    sudo systemctl disable ssh.socket 2>/dev/null || true
    sudo systemctl mask ssh.socket 2>/dev/null || true
    
    # 启用 SSH 服务
    sudo systemctl enable ssh
    sudo systemctl unmask ssh 2>/dev/null || true
    
    print_success "已切换到传统模式"
}

# ============================================================
# 5. 配置防火墙(UFW)
# ============================================================
configure_firewall() {
    print_info "配置 UFW 防火墙..."
    
    if command -v ufw &> /dev/null; then
        # 开放新端口
        sudo ufw allow $NEW_PORT/tcp comment 'SSH new port'
        
        # 如果旧端口是 22,也可以选择关闭(可选)
        # sudo ufw delete allow 22/tcp 2>/dev/null || true
        
        sudo ufw reload
        print_success "UFW 已开放端口 $NEW_PORT"
    else
        print_warning "UFW 未安装,请手动配置防火墙"
    fi
}

# ============================================================
# 6. 重启 SSH 服务
# ============================================================
restart_ssh() {
    print_info "重启 SSH 服务..."
    
    # 先检查配置语法
    if ! sudo sshd -t; then
        print_error "SSH 配置语法错误!"
        print_info "正在回滚..."
        rollback
        exit 1
    fi
    
    # 重启 SSH
    sudo systemctl restart ssh
    
    sleep 2
    
    # 验证服务状态
    if systemctl is-active ssh &>/dev/null; then
        print_success "SSH 服务运行正常"
    else
        print_error "SSH 服务启动失败!"
        sudo journalctl -u ssh -n 10 --no-pager
        print_info "正在回滚..."
        rollback
        exit 1
    fi
}

# ============================================================
# 7. 验证端口
# ============================================================
verify_port() {
    print_info "验证端口监听状态..."
    sleep 2
    
    if ss -tulnp | grep -q ":$NEW_PORT "; then
        print_success "端口 $NEW_PORT 正在监听"
        ss -tulnp | grep ":$NEW_PORT "
        return 0
    else
        print_error "端口 $NEW_PORT 未监听!"
        print_info "当前监听端口:"
        ss -tulnp | grep ssh
        rollback
        exit 1
    fi
}

# ============================================================
# 8. 本地测试
# ============================================================
test_local() {
    print_info "本地测试 SSH 连接..."
    sleep 2
    
    if ssh -p $NEW_PORT -o ConnectTimeout=5 -o BatchMode=yes localhost exit 2>/dev/null; then
        print_success "本地连接测试成功(密钥)"
        return 0
    else
        print_warning "本地密钥认证测试失败"
        print_info "尝试密码认证测试..."
        if ssh -p $NEW_PORT -o ConnectTimeout=5 -o PreferredAuthentications=password localhost exit 2>/dev/null; then
            print_success "本地连接测试成功(密码)"
            print_warning "⚠️ 密码认证仍然可用,请检查配置"
        else
            print_warning "本地连接测试失败(预期行为,密码已禁用)"
        fi
    fi
}

# ============================================================
# 9. 回滚函数
# ============================================================
rollback() {
    print_error "正在回滚配置..."
    
    if [ -f "$BACKUP_DIR/sshd_config.bak" ]; then
        sudo cp "$BACKUP_DIR/sshd_config.bak" /etc/ssh/sshd_config
        print_info "SSH 配置已恢复"
    fi
    
    sudo systemctl unmask ssh.socket 2>/dev/null || true
    sudo systemctl restart ssh 2>/dev/null || true
    
    print_warning "回滚完成,请使用原端口连接"
    exit 1
}

# ============================================================
# 10. 最终信息
# ============================================================
show_summary() {
    # 获取服务器 IP
    SERVER_IP=$(curl -s ifconfig.me 2>/dev/null || curl -s ipinfo.io/ip 2>/dev/null || echo "你的服务器IP")
    
    echo ""
    echo "=========================================="
    print_success "SSH 端口配置完成!"
    echo "=========================================="
    echo ""
    echo "  ✅ 模式: 传统 Service 模式"
    echo "  ✅ 端口: $NEW_PORT"
    echo "  ✅ 认证: 仅公钥(密码已禁用)"
    echo ""
    echo "  连接命令:"
    echo "  ssh -p $NEW_PORT root@$SERVER_IP"
    echo ""
    echo "  本地测试:"
    echo "  ssh -p $NEW_PORT root@localhost"
    echo ""
    echo "  备份目录: $BACKUP_DIR"
    echo ""
    echo "  ⚠️  重要提醒:"
    echo "  1. 请在另一个终端测试新端口连接"
    echo "  2. 确认连接成功后再关闭当前会话"
    echo "  3. 云服务器请在安全组放行 $NEW_PORT 端口"
    echo "  4. 如需恢复: cp $BACKUP_DIR/sshd_config.bak /etc/ssh/sshd_config"
    echo ""
    echo "=========================================="
}

# ============================================================
# 11. 主流程
# ============================================================
main() {
    echo ""
    echo "=========================================="
    echo "  Ubuntu SSH 端口切换(传统模式)"
    echo "  目标端口: $NEW_PORT"
    echo "=========================================="
    echo ""
    
    # 检查 root 权限
    if [ "$EUID" -ne 0 ]; then 
        print_error "请使用 root 或 sudo 运行此脚本"
        exit 1
    fi
    
    # 执行步骤
    check_port
    backup_config
    configure_ssh
    switch_to_traditional
    configure_firewall
    restart_ssh
    verify_port
    test_local
    show_summary
}

# 运行主流程
main "$@"